package com.qf.mybatisplus.aspect;

import com.qf.mybatisplus.utils.DesUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

/**
 * @ClassName: EncryptAspect
 * @Author:Cola.Niu
 * @date:2020/4/22 0:39
 * @Version:v1.0
 * @description: 加密切面
 */
@Aspect
@Component
public class EncryptAspect {
    private final static Logger logger = LoggerFactory.getLogger(EncryptAspect.class);

    @Pointcut("@annotation(com.qf.mybatisplus.aspect.Encrypt)")
    public void encryptPointCut() {
    }
    @SuppressWarnings("rawtypes")
    @Before("encryptPointCut()")
    public void before(JoinPoint point) throws Throwable {
        //获取参数列表
        Object[] args = point.getArgs();
        //获得参数注解列表
        MethodSignature signature= (MethodSignature) point.getSignature();
        Annotation[][] parameterAnnotaions = signature.getMethod().getParameterAnnotations();

        boolean flag = false;//参数是否是字符串
        for(int i = 0; i < parameterAnnotaions.length; i++) {
            Annotation[] oneParameterAnnotaions = parameterAnnotaions[i];

            for (int j = 0; j < oneParameterAnnotaions.length; j++) {
                //判断是否包含@EncryptParam注解
                if (oneParameterAnnotaions[j].annotationType() == EncryptParam.class) {
                    //判断参数类型
                    if(args[i] instanceof String){
                        args[i] = DesUtil.encrypt((String)args[i]);
                        flag = true;
                    }else {
                        encrypt(args[i]);
                    }
                }
            }
        }
        if (flag){
            ((ProceedingJoinPoint)point).proceed(args);
        }

    }

    /**
     * 将对象o上有@EncryptParam注解的属性进行加密
     * @param o
     */
    private void encrypt(Object o){
        Class c = o.getClass();
        //获得所有的属性
        Field[] fields =  c.getDeclaredFields();
        for (Field field : fields) {
            //判断是否存在EncryptParam注解
            if (field.getAnnotation(EncryptParam.class)!=null){
                //对该字段进行加密
                field.setAccessible(true);
                try {
                    //只对String类型加密
                    if (field.get(o) instanceof String){
                        field.set(o, DesUtil.encrypt((String)field.get(o)));
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
